package com.zmn.oms.dubbo.impl.callcenter;

import com.zmn.consts.GlobalConsts;
import com.zmn.oms.business.interfaces.es.OrderWorkEsBService;
import org.apache.dubbo.config.annotation.Service;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.zmn.common.constant.OrderGlobalConsts;
import com.zmn.common.dto.ResponseDTO;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.math.MathUtil;
import com.zmn.common.utils.response.ResponseUtil;
import com.zmn.common.utils.validator.ValidateResult;
import com.zmn.common.utils.validator.ValidatorUtil;
import com.zmn.oms.common.constant.OrderConsts;
import com.zmn.oms.dubbo.dto.zmn.callcenter.dio.PerfStaffDIO;
import com.zmn.oms.dubbo.dto.zmn.callcenter.dro.PerfStaffDRO;
import com.zmn.oms.dubbo.interfaces.callcenter.PerfStaffRemoteService;
import com.zmn.oms.dubbo.utils.DubboConsts;
import com.zmn.oms.model.bo.work.EsQueryBuilder;
import com.zmn.oms.model.entity.work.OrderWorkQuery;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.filter.FilterAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.filter.ParsedFilter;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

/**
 * 类描述：员工绩效
 * @author lujia
 * @date 2019/5/20 9:36
 */
@Service(loadbalance = "roundrobin", timeout = 5000, retries = 2, version = DubboConsts.INTERFACE_VERSION, validation = "false")
@Slf4j
public class PerfStaffRemoteServiceImpl implements PerfStaffRemoteService {

    @Resource
    private OrderWorkEsBService orderWorkEsBService;

    static final String TAG = "呼叫-员工绩效";

    @Override
    public ResponseDTO<PerfStaffDRO> findPerfStaffOrderCount(PerfStaffDIO perfStaffDIO) {

        log.info("[{}] 员工绩效：{}", TAG, perfStaffDIO);
        ValidateResult validateResult = ValidatorUtil.validator(perfStaffDIO);
        if (!validateResult.isSuccess()) {
            log.error("[{}] 参数错误：{}", TAG, validateResult.toString());
            return ResponseUtil.responseFail("提交参数错误");
        }

        // 初始化map
        Map<String, PerfStaffDRO> initMap = init(perfStaffDIO.getStaffIdList());

        try {

            // 新单
            this.queryNewOrder(perfStaffDIO, initMap);

            // 返修单
            this.queryReworkOrder(perfStaffDIO, initMap);

            // 回访单
            this.queryReplyOrder(perfStaffDIO, initMap);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return ResponseUtil.responseFail();
        }
        return ResponseUtil.responseSuccessItems(Lists.newArrayList(initMap.values()));
    }

    private void queryReplyOrder(PerfStaffDIO perfStaffDIO, Map<String, PerfStaffDRO> initMap) throws Exception {
        String start = DateUtil.dateFormatToString(perfStaffDIO.getStartTime(), DateUtil.FORMAT_DEFAULT);
        String end = DateUtil.dateFormatToString(perfStaffDIO.getEndTime(), DateUtil.FORMAT_DEFAULT);

        // 返修
        OrderWorkQuery query = new OrderWorkQuery();
        query.setPageSize(1);
        query.setReplyVisitTime(start + "," + end);
        query.setReplyVisiterIdList(perfStaffDIO.getStaffIdList());

        BoolQueryBuilder queryBuilder = EsQueryBuilder.getQuery(query);
        NativeSearchQuery searchQuery = new NativeSearchQuery(queryBuilder);
        searchQuery.setPageable(EsQueryBuilder.getPageRequest(query));

        TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms("operator_id").field("replyVisiterId").size(10000);
        searchQuery.addAggregation(termsAggregationBuilder);

        Aggregations aggregations = orderWorkEsBService.getAggregationsByQuery(searchQuery);
        ParsedLongTerms operator_id = aggregations.get("operator_id");
        List<? extends Terms.Bucket> buckets = operator_id.getBuckets();

        buckets.forEach(e -> {
            String key = e.getKeyAsString();
            long docCount = e.getDocCount();
            if (initMap.containsKey(key)) {
                initMap.get(key).setReplyOrderCount(docCount);
            }
        });
    }

    private void queryReworkOrder(PerfStaffDIO perfStaffDIO, Map<String, PerfStaffDRO> initMap) throws Exception {
        String start = DateUtil.dateFormatToString(perfStaffDIO.getStartTime(), DateUtil.FORMAT_DEFAULT);
        String end = DateUtil.dateFormatToString(perfStaffDIO.getEndTime(), DateUtil.FORMAT_DEFAULT);

        // 返修
        OrderWorkQuery query = new OrderWorkQuery();
        query.setPageSize(1);
        query.setReceiveTime(start + "," + end);
        query.setReceiverIdList(perfStaffDIO.getStaffIdList());
        query.setWorkType(Lists.newArrayList(OrderConsts.ORDER_TYPE_REWORK));

        BoolQueryBuilder queryBuilder = EsQueryBuilder.getQuery(query);
        NativeSearchQuery searchQuery = new NativeSearchQuery(queryBuilder);
        searchQuery.setPageable(EsQueryBuilder.getPageRequest(query));

        TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms("operator_id").field("receiverId").size(10000);
        searchQuery.addAggregation(termsAggregationBuilder);

        Aggregations aggregations = orderWorkEsBService.getAggregationsByQuery(searchQuery);
        ParsedLongTerms operator_id = aggregations.get("operator_id");
        List<? extends Terms.Bucket> buckets = operator_id.getBuckets();

        buckets.forEach(e -> {
            String key = e.getKeyAsString();
            long docCount = e.getDocCount();
            if (initMap.containsKey(key)) {
                initMap.get(key).setReworkOrderCount(docCount);
            }
        });
    }

    private void queryNewOrder(PerfStaffDIO perfStaffDIO, Map<String, PerfStaffDRO> initMap) throws Exception {

        String start = DateUtil.dateFormatToString(perfStaffDIO.getStartTime(), DateUtil.FORMAT_DEFAULT);
        String end = DateUtil.dateFormatToString(perfStaffDIO.getEndTime(), DateUtil.FORMAT_DEFAULT);

        // 新单
        OrderWorkQuery query = new OrderWorkQuery();
        query.setPageSize(1);
        query.setReceiveTime(start + "," + end);
        query.setWorkType(Lists.newArrayList(OrderConsts.ORDER_TYPE_NEW));
        query.setReceiverIdList(perfStaffDIO.getStaffIdList());
        query.setDuplicate(GlobalConsts.NO);

        BoolQueryBuilder queryBuilder = EsQueryBuilder.getQuery(query);
        NativeSearchQuery searchQuery = new NativeSearchQuery(queryBuilder);
        searchQuery.setPageable(EsQueryBuilder.getPageRequest(query));

        TermsAggregationBuilder termsAggregationBuilder = AggregationBuilders.terms("operator_id").field("receiverId").size(10000);
        FilterAggregationBuilder channelFilterAggregationBuilder = AggregationBuilders.filter("channelNewOrder", QueryBuilders.termQuery("channelId", perfStaffDIO.getChannelId()));
        FilterAggregationBuilder zmnFilterAggregationBuilder = AggregationBuilders.filter("zmnNewOrder", QueryBuilders.termQuery("platWork", GlobalConsts.PLAT_MARK_ZMN));
        FilterAggregationBuilder yeyxFilterAggregationBuilder = AggregationBuilders.filter("yeyxNewOrder", QueryBuilders.termQuery("platWork", GlobalConsts.PLAT_MARK_YEYX));
        FilterAggregationBuilder successFilterAggregationBuilder = AggregationBuilders.filter("successNewOrder", QueryBuilders.termQuery("resultStatus", OrderGlobalConsts.WORK_RESULT_SUCCESS));
        termsAggregationBuilder.subAggregation(zmnFilterAggregationBuilder);
        termsAggregationBuilder.subAggregation(yeyxFilterAggregationBuilder);
        termsAggregationBuilder.subAggregation(channelFilterAggregationBuilder);
        termsAggregationBuilder.subAggregation(successFilterAggregationBuilder);
        searchQuery.addAggregation(termsAggregationBuilder);

        Aggregations aggregations = orderWorkEsBService.getAggregationsByQuery(searchQuery);
        ParsedLongTerms operator_id = aggregations.get("operator_id");
        List<? extends Terms.Bucket> buckets = operator_id.getBuckets();

        buckets.forEach(e -> {
            String key = e.getKeyAsString();
            long docCount = e.getDocCount();
            ParsedFilter channelNewOrderFilter = e.getAggregations().get("channelNewOrder");
            ParsedFilter zmnNewOrderFilter = e.getAggregations().get("zmnNewOrder");
            ParsedFilter yeyxNewOrderFilter = e.getAggregations().get("yeyxNewOrder");
            ParsedFilter successNewOrderFilter = e.getAggregations().get("successNewOrder");

            Long newOrderCount = docCount;
            Long newOrderSuccessCount = successNewOrderFilter.getDocCount();

            Long newOrderSuccessRate = 0L;
            if (newOrderCount != 0) {
                newOrderSuccessRate = (long)(MathUtil.div(newOrderSuccessCount, newOrderCount, 4) * 10000);
            }

            if (initMap.containsKey(key)) {
                initMap.get(key).setNewOrderCount(docCount);
                initMap.get(key).setNewOrderSuccessCount(successNewOrderFilter.getDocCount());
                initMap.get(key).setNewOrderSuccessRate(newOrderSuccessRate);
                initMap.get(key).setChannelNewOrderCount(channelNewOrderFilter.getDocCount());
                initMap.get(key).setZmnNewOrderCount(zmnNewOrderFilter.getDocCount());
                initMap.get(key).setYeyxNewOrderCount(yeyxNewOrderFilter.getDocCount());
            }
        });

    }

    /**
     * 初始化
     * @param staffIdList
     * @return
     */
    private Map<String, PerfStaffDRO> init(List<Integer> staffIdList){
        Map<String, PerfStaffDRO> initMap = Maps.newHashMap();
        staffIdList.forEach(e -> {
            PerfStaffDRO dro = new PerfStaffDRO();
            dro.setStaffId(e);
            initMap.put(String.valueOf(e), dro);
        });
        return initMap;
    }
}
